#include "mdw_binary_calc.h"


/* ~~~~~~~~~~~~~~~ 创建/析构 ~~~~~~~~~~~~~~~~ */

/**
 * 初始化  
 * @param *self                 二值化计算器
 * @param inital_val            初始值（@ref MDW_TBinaryVal）
 * @param rising_thershold      上升沿判断阈值
 * @param falling_thershold     下降沿判断阈值    
 * @return  >=  0   成功；
 *          <   0   失败，上升沿阈值 <= 下降沿阈值
 */
Int32 MDW_TBinaryCalcCreate(MDW_TBinaryCalc *self, Int8 inital_val, Int32 rising_thershold, Int32 falling_thershold)
{
    Int32 result = -1;

    if (self != NULL)
    {
        self->binary_val_ = Mdw_kBinaryValInvalid;
        
        MDW_TBinaryCalcSetUpdataSourceValMethod(self, NULL, NULL);
        MDW_TBinaryCalcSetId(self, 0);
        
        if (MDW_TBinaryCalcSetThersholds(self, rising_thershold, falling_thershold))
        {
            self->binary_val_ = inital_val > 0 ? Mdw_kBinaryValOne : Mdw_kBinaryValZero;

            result = 1;
        }
        else
            result = -2;
    }

    return result;
}


/**
 * 析构  
 * @param *self         二值化计算器
 * @return 
 */
void MDW_TBinaryCalcDestroy(MDW_TBinaryCalc *self)
{
    if (self != NULL)
    {
        self->binary_val_ = Mdw_kBinaryValInvalid;
    }
}


/* ~~~~~~~~~~~~~~~ 属性方法 ~~~~~~~~~~~~~~~~~ */
Int32 MDW_TBinaryCalcSetId(MDW_TBinaryCalc *self, UInt8 id)
{
    self->id = id;
    return id;
}


/**
 * 读取上升沿阈值
 * @param *self     二值化计算器
 * @return  上升沿阈值
 */
Int32 MDW_TBinaryCalcRisingThershold(MDW_TBinaryCalc *self)
{
    return self->rising_thershold_;
}

/**
 * 设置上升沿阈值 
 * @param *self             二值化计算器
 * @param thershold_val     阈值
 * @return  == thershold_val 成功；
 *          != thershold_val 失败；
 */
Int32 MDW_TBinaryCalcSetRisingThershold(MDW_TBinaryCalc *self, Int32 thershold_val)
{
    if (thershold_val >= self->falling_thershold_)
        self->rising_thershold_ = thershold_val;

    return self->rising_thershold_;
}

/**
 * 读取下降沿阈值
 * @param *self     二值化计算器
 * @return  下降沿阈值
 */
Int32 MDW_TBinaryCalcFallingThershold(MDW_TBinaryCalc *self)
{
    return self->falling_thershold_;
}


/**
 * 设置下降沿阈值 
 * @param *self             二值化计算器
 * @param thershold_val     阈值
 * @return  == thershold_val 成功；
 *          != thershold_val 失败；
 */
Int32 MDW_TBinaryCalcSetFallingThershold(MDW_TBinaryCalc *self, Int32 thershold_val)
{
    if (self->rising_thershold_ >= thershold_val)
        self->falling_thershold_ = thershold_val;

    return self->falling_thershold_;
}

/**
 * 设置上升/下降沿阈值
 * @param *self             二值化计算器
 * @param rising_thershold  上升沿阈值 
 * @param falling_thershold 下降沿阈值
 * @return  True 成功
 *          False 失败
 */
Bool MDW_TBinaryCalcSetThersholds(MDW_TBinaryCalc *self, Int32 rising_thershold, Int32 falling_thershold)
{
    Bool result = rising_thershold >= falling_thershold;

    if (result)
    {
        Int8 tmp = self->binary_val_;

        self->binary_val_ = Mdw_kBinaryValInvalid;
        self->rising_thershold_ = rising_thershold;
        self->falling_thershold_ = falling_thershold;
        self->binary_val_ = tmp;
    }

    return result;
}

/**
 * 读取当前二值化值
 * @param *self
 * @return binary_val
 */
Int8 MDW_TBinaryCalcGetBinaryVal(MDW_TBinaryCalc *self)
{
    return self->binary_val_;
}


Int32 MDW_TBinaryCalcGetSourceVal(MDW_TBinaryCalc *self)
{
    return self->source_val_;
}

Bool MDW_TBinaryCalcSetUpdataSourceValMethod(MDW_TBinaryCalc *self, MDW_TBinaryCalcUpdataSourceValMethod method, void *user_param)
{
    Bool result = False;
    
    if (self != NULL)
    {
        self->DoUpdataSourceVal_ = method;
        self->user_param_ = user_param;
        result = True;
    }
        
    return result;
}


/* ~~~~~~~~~~~~~~~ 公有方法 ~~~~~~~~~~~~~~~~~ */

static Int8 L_MDW_TBinaryCalcSetSourceVal(MDW_TBinaryCalc *self, Int32 curr_source_val)
{
    self->source_val_ = curr_source_val;

    switch (self->binary_val_)
    {
        case Mdw_kBinaryValZero:
        {
            if (curr_source_val > self->rising_thershold_)
                self->binary_val_ = Mdw_kBinaryValOne;
            break;
        }

        case Mdw_kBinaryValOne:
        {
            if (curr_source_val < self->falling_thershold_)
                self->binary_val_ = Mdw_kBinaryValZero;
            break;
        }

        default:
            break;
    }

    return self->binary_val_;
}

MDW_TBinaryVal MDW_TBinaryCalcUpdateBinaryVal(MDW_TBinaryCalc *self)
{
    MDW_TBinaryVal result = Mdw_kBinaryValInvalid;
    
    if (self != NULL && self->DoUpdataSourceVal_ != NULL)
    {
        Int32 curr_source_val = self->DoUpdataSourceVal_(self, self->user_param_);
        result = (MDW_TBinaryVal)L_MDW_TBinaryCalcSetSourceVal(self, curr_source_val);
    }
    
    return result;
}


